///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __VertexIndexData_H__
#define __VertexIndexData_H__

#include "OgrePrerequisites.h"
#include "OgreHardwareVertexBuffer.h"
#include "OgreHardwareIndexBuffer.h"

namespace Ogre {
	
	

	/// Define a list of usage flags
	typedef vector<HardwareBuffer::Usage>::type BufferUsageList;


	
	class _OgreExport VertexData : public MemAlloc_Geometry
	{
    private:
        /// Protected copy constructor, to prevent misuse
        VertexData(const VertexData& rhs); /* do nothing, should not use */
        /// Protected operator=, to prevent misuse
        VertexData& operator=(const VertexData& rhs); /* do not use */

		HardwareBufferManagerBase* mMgr;
    public:
		
        VertexData(HardwareBufferManagerBase* mgr = 0);
		
		VertexData(VertexDeclaration* dcl, VertexBufferBinding* bind);
        ~VertexData();

		
		VertexDeclaration* vertexDeclaration;
		
		VertexBufferBinding* vertexBufferBinding;
		/// Whether this class should delete the declaration and binding
		bool mDeleteDclBinding;
		/// The base vertex index to start from
		size_t vertexStart;
		/// The number of vertices used in this operation
		size_t vertexCount;


		/// Struct used to hold hardware morph / pose vertex data information
		struct HardwareAnimationData
		{
			unsigned short targetBufferIndex;
			Real parametric;
		};
		typedef vector<HardwareAnimationData>::type HardwareAnimationDataList;
		/// VertexElements used for hardware morph / pose animation
		HardwareAnimationDataList hwAnimationDataList;
		/// Number of hardware animation data items used
		size_t hwAnimDataItemsUsed;
		
		
		VertexData* clone(bool copyData = true, HardwareBufferManagerBase* mgr = 0) const;

        
        void prepareForShadowVolume(void);

        
        HardwareVertexBufferSharedPtr hardwareShadowVolWBuffer;


		
		void reorganiseBuffers(VertexDeclaration* newDeclaration, const BufferUsageList& bufferUsage, 
			HardwareBufferManagerBase* mgr = 0);

		
		void reorganiseBuffers(VertexDeclaration* newDeclaration, HardwareBufferManagerBase* mgr = 0);

        
        void closeGapsInBindings(void);

        
        void removeUnusedBuffers(void);

		
		void convertPackedColour(VertexElementType srcType, VertexElementType destType);


		
		ushort allocateHardwareAnimationElements(ushort count, bool animateNormals);



	};

	
	class _OgreExport IndexData : public MemAlloc_Geometry
	{
    protected:
        /// Protected copy constructor, to prevent misuse
        IndexData(const IndexData& rhs); /* do nothing, should not use */
        /// Protected operator=, to prevent misuse
        IndexData& operator=(const IndexData& rhs); /* do not use */
    public:
        IndexData();
        ~IndexData();
		/// pointer to the HardwareIndexBuffer to use, must be specified if useIndexes = true
		HardwareIndexBufferSharedPtr indexBuffer;

		/// index in the buffer to start from for this operation
		size_t indexStart;

		/// The number of indexes to use from the buffer
		size_t indexCount;

		
		IndexData* clone(bool copyData = true, HardwareBufferManagerBase* mgr = 0) const;

		
		void optimiseVertexCacheTriList(void);
	
	};

	
	class _OgreExport VertexCacheProfiler : public MemAlloc_RenderSys
    {
		public:
			enum CacheType {
				FIFO, LRU
			};

			VertexCacheProfiler(unsigned int cachesize = 16, CacheType cachetype = FIFO )
				: size ( cachesize ), type ( cachetype ), tail (0), buffersize (0), hit (0), miss (0)
			{
				cache = PH_ALLOC_T(uint32, size, Memory::ResourceHeap);
			}

			~VertexCacheProfiler()
			{
				PH_FREE(cache, Memory::ResourceHeap);
			}

			void profile(const HardwareIndexBufferSharedPtr& indexBuffer);
			void reset() { hit = 0; miss = 0; tail = 0; buffersize = 0; }
			void flush() { tail = 0; buffersize = 0; }

			unsigned int getHits() { return hit; }
			unsigned int getMisses() { return miss; }
			unsigned int getSize() { return size; }
		private:
			unsigned int size;
			uint32 *cache;
			CacheType type;

			unsigned int tail, buffersize;
			unsigned int hit, miss;

			bool inCache(unsigned int index);
	};
	
	
}
#endif

